package com.vip.common.service.impl;

import com.vip.common.config.MinioConfig;
import com.vip.common.service.CommonMinioService;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ASUS
 * @Date 2025/3/28 12:26
 * @Descripition TODO
 */
@Service
public class CommonMinioServiceImpl implements CommonMinioService {
    @Resource
    private MinioClient minioClient;

    @Resource
    private MinioConfig minioConfig;
    private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;

    @Override
    public boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    @Override
    public boolean createBucket(String bucketName) throws Exception {
        boolean exists = bucketExists(bucketName);
        if (!exists) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteBucket(String bucketName) throws Exception {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                if (item.size() > 0)
                    return false;
            }
            // 删除存储桶，注意，只有存储桶为空时才能删除成功。
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
            flag = bucketExists(bucketName);
            return !flag;
        } else return false;
    }

    @Override
    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
        return bucketExists(bucketName) ? minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build()) : null;
    }

    @Override
    public List<String> listBucketName() throws Exception {
        List<String> bucketNames = new ArrayList<>();
        List<Bucket> bucketList = minioClient.listBuckets();
        for (Bucket bucket : bucketList) {
            bucketNames.add(bucket.name());
        }
        return bucketNames;
    }

    @Override
    public List<String> listObjectNames(String bucketName) throws Exception {
        List<String> objectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> results = listObjects(bucketName);
            for (Result<Item> result : results) {
                Item item = result.get();
                objectNames.add(item.objectName());
            }
            return objectNames;
        }
        return objectNames;
    }

    @Override
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
        return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    @Override
    public String getPresignedObjectUrl(String fileName) throws Exception {
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .expiry(DEFAULT_EXPIRY_TIME)
                .build());
    }

    @Override
    public String getObjectUrl(String objectName) throws Exception {
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(minioConfig.getBucketName())
                .object(objectName)
                .build());
    }

    @Override
    public String getObjectUrl(String objectName, Integer expires) throws Exception {
        if (expires < 1 || expires > DEFAULT_EXPIRY_TIME)
            throw new IllegalArgumentException("expires must be between 1 and 604800");
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(minioConfig.getBucketName())
                .object(objectName)
                .expiry(expires, TimeUnit.HOURS)//设置过期时间
                // .expiry(24 * 60 * 60)//用秒来计算一天时间有效期
                // .expiry(1, TimeUnit.DAYS)//按天传参
                // .expiry(1, TimeUnit.HOURS)//按小时传参数
                .build());
    }

    @Override
    public void downloadObject(HttpServletResponse response, String objectName) throws Exception {
        InputStream file = minioClient.getObject(GetObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(objectName)
                .build());
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName, StandardCharsets.UTF_8));
        ServletOutputStream servletOutputStream = response.getOutputStream();
        int len;
        byte[] buffer = new byte[1024];
        while ((len = file.read(buffer)) > 0) {
            servletOutputStream.write(buffer, 0, len);
        }
        servletOutputStream.flush();
        file.close();
        servletOutputStream.close();
    }

    @Override
    public boolean downloadObject(String objectName, String fileName) throws Exception {
        StatObjectResponse statObject = getObjectInfo(minioConfig.getBucketName(), objectName);
        if (statObject != null && statObject.size() > 0) {
            minioClient.downloadObject(DownloadObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .filename(fileName)
                    .build());
            return true;
        }
        return false;
    }

    @Override
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        StatObjectResponse statObjectResponse = getObjectInfo(bucketName, objectName);
        if (statObjectResponse != null && statObjectResponse.size() > 0)
            return minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());

        return null;
    }

    @Override
    public InputStream getObject(String bucketName, String objectName, long offset, Long length) throws Exception {
        StatObjectResponse statObjectResponse = getObjectInfo(bucketName, objectName);
        if (statObjectResponse != null && statObjectResponse.size() > 0)
            return minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .offset(offset)
                    .length(length)
                    .build());
        return null;
    }

    @Override
    public boolean removeObject(String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(objectName)
                .build());
        return true;
    }

    @Override
    public List<String> removeObjects(String bucketName, List<DeleteObject> objectNames) throws Exception {
        List<String> deleteErrorNames = new ArrayList<>();
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objectNames).build());
        for (Result<DeleteError> result : results) {
            DeleteError error = result.get();
            deleteErrorNames.add(error.objectName());
        }
        return deleteErrorNames;
    }

}
